package com.jbp.service;

import com.alibaba.fastjson.JSON;
import com.google.gson.reflect.TypeToken;
import com.jbp.domin.LuckReq2;
import com.jbp.exception.RRException;
import com.jbp.model.Gift;
import com.jbp.model.Pool;
import com.jbp.model.PoolRoom;
import com.jbp.model.User;
import com.jbp.redis.RedisConfigService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class LuckVUtil2 {
    @Autowired
    private RedisConfigService redisConfigService;
    @Autowired
    private PoolGiftConfigService poolGiftConfigService;
    @Autowired
    private GiftService giftService;
    @Autowired
    private UserDailyLuckRecordService userDailyLuckRecordService;
    @Autowired
    private PoolRoomService poolRoomService;
    @Autowired
    private UserService userService;
    @Autowired
    private PrizePatchService prizePatchService;

    @Autowired
    private AppConfigService appConfigService;

    public List<Gift> luck(LuckReq2 luckReq, Pool pool, Integer poolXUserId) {
        String key = "kchat:pool:" + luckReq.getPrice();
        //看用户是否有指定奖池
        if (pool.getType() != 0) {
            key = key + ":poolXUserId=" + poolXUserId;
        }
        key = key + ":pool=" + pool.getId();
        //是否个池
        if (pool.getCom() != 1) {
            key = key + ":userid=" + luckReq.getUserId();
        }

        List<Gift> gifts = new ArrayList<>();

        User user = userService.getById(luckReq.getUserId());

        Map<Integer, Gift> giftMap = new HashMap<>();

        //限制盈利
        HashMap<String, BigDecimal> winMap = new HashMap<>();
        int maxGift = getMaxGift(luckReq, winMap, user.getIp(), user.getDevice());

        //抽奖
        for (Integer i = 0; i < luckReq.getTimes(); i++) {
            //取奖池
            while (true) {
                Map<Integer, Integer> map = getPool(key, pool);
                int giftId = doLuck(map, 200000, 0, giftMap);
                updatePool(key, map);
                if (giftId == 0) {
                    throw new RRException("网络错误1003");
                }

                if (!giftMap.containsKey(giftId)) {
                    Gift gift = giftMap.get(giftId);
                    if (gift == null) {
                        gift = giftService.getById(giftId);
                        giftMap.put(giftId, gift);
                    }
                }

                Gift gift = giftMap.get(giftId);
                if(gift.getCoin()<=maxGift) {
                    Gift out = new Gift();
                    BeanUtils.copyProperties(gift, out);
                    gifts.add(out);
                    break;
                }
            }
        }

        //保105
        protect105(luckReq, gifts, pool.getId());

        //回血 最大亏损
//        addBlood(luckReq, gifts, map, giftMap);
//        tjResult(gifts);
        return gifts;
    }

    //计算最大礼物
    private int getMaxGift(LuckReq2 luckReq, HashMap<String, BigDecimal> winMap, String ip, String device) {

        int maxWinUser = Integer.parseInt(appConfigService.getVForCache("maxWinUser"));
        //user
        if (winMap.get("userPay") == null || winMap.get("userIncome") == null) {
            HashMap<String, BigDecimal> userMap = userDailyLuckRecordService.getLuckByUser(luckReq.getUserId());
            winMap.put("userIncome", userMap.get("income"));
            winMap.put("userPay", userMap.get("pay"));
        }
        int winUser = (int) (winMap.get("userIncome").doubleValue() * 0.85d - winMap.get("userPay").intValue());
        int maxUser = Math.max(maxWinUser - winUser, 2000);

        int maxWinRoom = Integer.parseInt(appConfigService.getVForCache("maxWinRoom"));
        int maxWinDevice = Integer.parseInt(appConfigService.getVForCache("maxWinDevice"));
        //room
        if (winMap.get("roomPay")==null || winMap.get("roomIncome")==null) {
            HashMap<String, BigDecimal> roomMap = userDailyLuckRecordService.getLuckByRoomId(luckReq.getRoomId());
            winMap.put("roomIncome",roomMap.get("income"));
            winMap.put("roomPay",roomMap.get("pay"));
        }
        int winRoom = (int) (winMap.get("roomIncome").doubleValue() * 0.85d - winMap.get("roomPay").intValue());
        int maxRoom = Math.max(maxWinRoom-winRoom, 2000);

        // room Rate
        if (winMap.get("roomRate")==null) {
            PoolRoom poolRoom = poolRoomService.getByRoomId(luckReq.getRoomId());
            if (poolRoom != null) {
                winMap.put("roomRate", poolRoom.getRate());
            } else {
                winMap.put("roomRate", BigDecimal.ZERO);
            }
        }
        if (winMap.get("roomRate") != null && winMap.get("roomRate").intValue()!=0) {
            if (winMap.get("roomIncome").divide(winMap.get("roomPay"), 4, 2).doubleValue() > winMap.get("roomRate").doubleValue()) {
                maxRoom = 2000;
            }
        }

        // ip
        if (winMap.get("ipPay")==null || winMap.get("ipIncome")==null) {
            HashMap<String, BigDecimal> ipMap = userDailyLuckRecordService.getLuckByIp(ip);
            winMap.put("ipIncome",ipMap.get("income"));
            winMap.put("ipPay",ipMap.get("pay"));
        }
        int winIp = (int) (winMap.get("ipIncome").doubleValue() * 0.85d - winMap.get("ipPay").intValue());
        int maxIp = Math.max(maxWinDevice-winIp, 2000);

        // device
        if (winMap.get("devicePay")==null || winMap.get("deviceIncome")==null) {
            HashMap<String, BigDecimal> deviceMap = userDailyLuckRecordService.getLuckByDevice(device);
            winMap.put("deviceIncome",deviceMap.get("income"));
            winMap.put("devicePay",deviceMap.get("pay"));
        }

        int winDevice =  (int) (winMap.get("deviceIncome").doubleValue() * 0.85d - winMap.get("devicePay").intValue());
        int maxDevice = Math.max(maxWinDevice-winDevice, 2000);

        return Math.min(Math.min(maxDevice, maxIp), Math.min(maxRoom, maxUser));
    }

    private void checkRate(LuckReq2 luckReq, List<Gift> gifts, Integer poolId) {
        PoolRoom poolRoom = poolRoomService.getByRoomId(luckReq.getRoomId());
        if (poolRoom != null) {
            //检查抽奖后爆率
            HashMap<String, BigDecimal> map = userDailyLuckRecordService.getLuckByRoomId(luckReq.getRoomId());
            Integer pay = map.get("pay").intValue();
            Integer income = map.get("income").intValue();
            int totalPay = pay + gifts.size() * luckReq.getPrice();
            int totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();
            System.out.println("pay:"+totalPay+" in:"+totalIncome);
            if (BigDecimal.valueOf(totalIncome).divide(BigDecimal.valueOf(totalPay), 4, 2).doubleValue() > poolRoom.getRate().doubleValue()) {
                List<Gift> configGifts = poolGiftConfigService.getGiftsByPoolId(poolId).stream().filter(gift -> gift.getCoin()<6000).collect(Collectors.toList());
                Gift minGift = configGifts.stream().min(Comparator.comparingInt(Gift::getCoin)).get();
                for (Gift gift : gifts) {
                    if (gift.getCoin() > poolRoom.getMaxGift() && gift.getCoin() > minGift.getCoin()) {
                        System.out.println(gift.getCoin() + "->" + minGift.getCoin());
                        BeanUtils.copyProperties(minGift, gift);
                        totalIncome = totalIncome - gift.getCoin() + minGift.getCoin();
                        if (BigDecimal.valueOf(totalIncome).divide(BigDecimal.valueOf(totalPay), 4, 2).doubleValue() <= poolRoom.getRate().doubleValue()) {
                            break;
                        }
                    }
                }
            }
        }
    }

    /**是否需要回血*/
    private void addBlood(LuckReq2 luckReq, List<Gift> gifts, Map<Integer, Integer> m, Map<Integer, Gift> giftMap) {
        //有待补的 就不要再补
        boolean flag = prizePatchService.hasNormalGift(luckReq.getUserId());
        if (flag) {
            return;
        }

        HashMap<String, BigDecimal> map = userDailyLuckRecordService.getLuckByType(luckReq.getUserId(), luckReq.getPrice());
        Integer pay = map.get("pay").intValue();
        Integer income = map.get("income").intValue();
        int totalPay = pay + gifts.size() * luckReq.getPrice();
        int totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();

        //10w以下最多亏1万  10w以上最多亏2w
        int lose = (int) (totalPay-totalIncome*0.85d);
        int luckId = 0;
        if (totalPay<=1000000 && lose>80000) {
            //回5000-30000
            luckId = doLuck(m, 30000, 5000, giftMap);
        } else if (totalPay>1000000 && lose>160000) {
            //回10000-80000
            luckId = doLuck(m, 80000, 10000, giftMap);
        }
        if (luckId!=0) {
            //替换一个抽取到的礼物
            Gift luck = giftService.getById(luckId);
            System.out.println("补礼物："+luck.getCoin());
            BeanUtils.copyProperties(luck, gifts.get(0));
        }
    }

    /**保105*/
    private void protect105(LuckReq2 luckReq, List<Gift> gifts, Integer poolId) {
        //20奖池  投入100000-101000 rate<1.05
        if (luckReq.getPrice() == 20) {
            HashMap<String, BigDecimal> map = userDailyLuckRecordService.getLuckByType(luckReq.getUserId(), luckReq.getPrice());
            Integer pay = map.get("pay").intValue();
//            pay = 100000;
            if (pay !=null && pay.intValue()>=200000 && pay.intValue()<=200200){
                Integer income = map.get("income").intValue();
//                income = 50000+new Random().nextInt(70000);
                int totalPay = pay + gifts.size() * luckReq.getPrice();
                int totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();
                //抽奖后爆率
                if (!checkRate105(totalPay, totalIncome)) {
                    List<Gift> configGifts = poolGiftConfigService.getGiftsByPoolId(poolId).stream().filter(gift -> gift.getCoin()<6000).collect(Collectors.toList());
                    Collections.reverse(configGifts);
                    for (Gift gift : gifts) {
                        //再次检查整体爆率
                        if (!checkRate105(totalPay, totalIncome)) {
                            //取一个新礼物  替换后  用户超过105 不超过500钻 否则就取小于105最大的
                            for (Gift configGift : configGifts) {
                                int incomeIfReplace = totalIncome-gift.getCoin()+configGift.getCoin();
                                if (checkRate105(totalPay, incomeIfReplace)) {
                                    if (incomeIfReplace < (totalPay*1.0d + 500)) {
                                        totalIncome = incomeIfReplace;
                                        BeanUtils.copyProperties(configGift, gift);
                                        break;
                                    }
                                } else {
                                    totalIncome = incomeIfReplace;
                                    BeanUtils.copyProperties(configGift, gift);
                                    break;
                                }
                            }
                        } else {
                            break;
                        }
                    }

                    //替换后校验  如果爆率大于1.08  异常
                    totalPay = pay + gifts.size() * luckReq.getPrice();
                    totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();
//                    printRate("end", totalPay, totalIncome);
                    if(BigDecimal.valueOf(totalIncome).divide(BigDecimal.valueOf(totalPay), 4, 2).doubleValue() > 1.08) {
                        throw new RRException("错误10002");
                    }


                }
            }
        }

        //最大亏200000  2w
    }

    /*private void protect105(LuckReq2 luckReq, List<Gift> gifts, Integer poolId) {
        //20奖池  投入100000-101000 rate<1.05
        if (luckReq.getPrice() == 20) {
            HashMap<String, BigDecimal> map = userDailyLuckRecordService.getLuckByType(luckReq.getUserId(), luckReq.getPrice());
            Integer pay = map.get("pay").intValue();
//            pay = 100000;
            if (pay !=null && pay.intValue()>=100000 && pay.intValue()<=103000){
                Integer income = map.get("income").intValue();
//                income = 50000+new Random().nextInt(70000);
                int totalPay = pay + gifts.size() * luckReq.getPrice();
                int totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();
                //抽奖后爆率
                if (!checkRate105(totalPay, totalIncome)) {
                    List<Gift> configGifts = poolGiftConfigService.getGiftsByPoolId(poolId).stream().filter(gift -> gift.getCoin()<6000).collect(Collectors.toList());
                    Collections.reverse(configGifts);
                    for (Gift gift : gifts) {
                        //再次检查整体爆率
                        if (!checkRate105(totalPay, totalIncome)) {
                            //取一个新礼物  替换后  用户超过105 不超过500钻 否则就取小于105最大的
                            for (Gift configGift : configGifts) {
                                int incomeIfReplace = totalIncome-gift.getCoin()+configGift.getCoin();
                                if (checkRate105(totalPay, incomeIfReplace)) {
                                    if (incomeIfReplace < (totalPay*1.05d + 500)) {
                                        totalIncome = incomeIfReplace;
                                        BeanUtils.copyProperties(configGift, gift);
                                        break;
                                    }
                                } else {
                                    totalIncome = incomeIfReplace;
                                    BeanUtils.copyProperties(configGift, gift);
                                    break;
                                }
                            }
                        } else {
                            break;
                        }
                    }

                    //替换后校验  如果爆率大于1.08  异常
                    totalPay = pay + gifts.size() * luckReq.getPrice();
                    totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();
//                    printRate("end", totalPay, totalIncome);
                    if(BigDecimal.valueOf(totalIncome).divide(BigDecimal.valueOf(totalPay), 4, 2).doubleValue() > 1.08) {
                        throw new RRException("错误10002");
                    }
                }
            }
        }

        //最大亏200000  2w
    }*/

    private void  printRate(String prex, int pay, int income) {
        System.out.println(prex+" pay:"+ pay +"  income:"+income + " r:"+BigDecimal.valueOf(income).divide(BigDecimal.valueOf(pay), 4, 2).doubleValue());
    }
    //是否大于105爆率
    private boolean checkRate105(int pay, int income) {
//        return BigDecimal.valueOf(income).divide(BigDecimal.valueOf(pay), 4, 2).doubleValue() > 1.05;
        return BigDecimal.valueOf(income).divide(BigDecimal.valueOf(pay), 4, 2).doubleValue() > 1.0;
    }

    /**打印抽奖结果*/
    private void tjResult(List<Gift> gifts){
        Map<Integer, Integer> map = new HashMap<>();
        for (Gift gift : gifts) {
            Integer coin = gift.getCoin();
            if (map.containsKey(coin)) {
                map.put(coin, map.get(coin)+1);
            } else {
                map.put(coin, 1);
            }
        }
        System.out.println(JSON.toJSON(map));
    }

    //随机数
    private int doLuck(Map<Integer, Integer> map, int maxGift, int minGift, Map<Integer, Gift> giftMap) {
        Map<Integer, Integer> filterMap = null;
        if(minGift>0) {
            filterMap = map.entrySet().stream()
                    .filter(e -> {
                        Gift gift = giftMap.get(e.getKey());
                        return gift.getCoin() <= maxGift && gift.getCoin() >= minGift;
                    })
                    .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
        } else {
            filterMap = map.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
        }
        int sum = filterMap.values().stream().mapToInt(Integer::intValue).sum();
        if (sum<=0) {
            return 0;
        }
        int i = new Random().nextInt(sum);
        int t = 0;
        for (Map.Entry<Integer, Integer> entry : filterMap.entrySet()) {
            t += entry.getValue();
            if (i<t) {
                map.put(entry.getKey(), entry.getValue()-1);
                return entry.getKey();
            }
        }
        return 0;
    }

    //获取奖池
    public Map<Integer, Integer> getPool(String key, Pool pool){
        Type type = new TypeToken<Map<Integer, Integer>>(){}.getType();
        Map<Integer, Integer> map = (Map<Integer, Integer>) redisConfigService.getJson(key, type);
        //如果奖池空了
        if (map == null|| map.values().stream().mapToInt(Integer::intValue).sum() <=0) {
            map = poolGiftConfigService.getPoolGifts(pool);
        } /*else if (map.values().stream().mapToInt(Integer::intValue).sum() <= 2000) {
            Map<Integer, Integer> addMap = poolGiftConfigService.getPoolGifts(pool);
            for (Map.Entry<Integer, Integer> e : addMap.entrySet()) {
                if (map.containsKey(e.getKey())) {
                    map.put(e.getKey(), e.getValue() + map.get(e.getKey()));
                } else {
                    map.put(e.getKey(), e.getValue());
                }
            }
        }*/
        return map;
    }

    //跟新奖池
    public void updatePool(String key, Map<Integer, Integer> map) {
        redisConfigService.setJson(key, map);
    }
}
